ArcGIS Runtime for Android 使用異步GP服務繪製等值線

關於基於Android上ArcGIS Server GP服務的調用,已經有前輩給出了很好的例子:html

http://blog.csdn.net/esrichinacd/article/details/9231815java

以及官方的幫助文檔:android

https://developers.arcgis.com/android/sample-code/viewshed/web

詳細經過仔細學習上面的內容,您也能夠基本瞭解GP服務的使用過程。算法

本文咱們主要將如下三部份內容:api

1.學會使用使用ArcMap構建等值線GP服務模型服務器

2.學會使用ArcGIS Server發佈咱們建立的GP服務模型異步

3.學會ArcGIS Runtime for Android下異步調用GP服務,繪製等值線ide

 其中前兩部分可本博客其餘文章有詳細說明可參考:函數

http://www.cnblogs.com/potential/archive/2012/10/27/2742355.html

這篇文章使用的是10.0的ArcGIS Server,而這裏咱們使用的是10.1的 ArcGIS Server,所以在此咱們也會提到10.1下如何來發布咱們的服務。若是您熟悉GP服務的發佈過程,可直接跳轉至第三部分。

 

第三部分的內容主要解決如下幾個問題:

1.若是根據現有的座標信息和對應的屬性數據,構造相應的地理要素?例如:如今有某個省的個監測點的降雨數據(監測點經緯度,及監測點的降雨量),那麼如何在地圖上對這些監測點的數據進行反映?

2.如何在Android平臺上根據這些監測點的數據來對整個地區進行插值呢?並將等值線添加到Android移動平臺的地圖中?

3.如何根據等值線的值,動態設置其不一樣的顏色呢?

 

1、使用ArcMap構建等值線的GP服務模型

 

既然咱們要建立等值線那麼,確定須要繪製等值線的數據,即進行等值線繪製的點。而等值線又是怎麼獲得的呢?很簡單,根據這些點的位置和其表示的值(如該店的降雨量,濃度值等)對其進行插值。插值的過程就是根據已有的點來計算某一未知區域的點的濃度值。

經常使用的插值方法有拉格朗日插值,克里金插值,反距離插值,樣條函數插值等。通常狀況下咱們選擇反距離和克里金插值,若是想獲得很是平滑的插值結果,則能夠採用三次樣條插值。

      插值完成以後,實際上獲得的是更多的點,而繪製等值線就是將具備相同屬性值的點鏈接起來獲得等值線。一般狀況下咱們須要本身代碼完成插值過程和追蹤等值點的算法。並鏈接等值點。可是在ArcGIS中有內置的插值工具和等值線工具供咱們使用。可是在ArcGIS中各個功能模塊都是一個單獨的工具,而經過上面的分析咱們知道繪製等值線至少有兩個過程:1.插值,2.依據插值結果繪製等值線

     所以依據上面的分析咱們經過ArcMap的Model Builder能夠構建以下的工具模型:

   

 

     可是一般狀況下上述獲得的等值線有可能不會很平滑,若是須要較平滑的等值線能夠再加上一個平滑工具,如:

  

       經過加上平滑工具,設置平滑容差,能夠獲得較爲平滑的等值線。

 

2、  發佈GArcMap構建的GP服務模型

 

      在ArcGIS Server 10.1中,發佈GP服務的方式較以前有所改變,再也不是發佈GP服務模型自己,而是發佈在GP服務模型在ArcMap運行以後的結果,如圖所示:

    

    

        而後出現發佈服務的選項:

     

  

  •      publish a service:直接將現有模型結果發佈爲GP服務。
  •      Save a service definition file:保存爲服務定義文件,能夠用於在ArcGIS Server Manager中發佈爲服務。
  •      Overwrite an existing service:覆蓋當前的ArcGIS Server 服務。

  • 這裏咱們選擇第二個選項,Save a service definition file.這樣的好處是能夠在ArcGIS Manager上遠程發佈。同時sd文件也很容易遷移到其餘的機器。

      保存爲sd文件以後,登錄ArcGIS Server Manager頁面,點擊發布服務:

     

      

       而後點擊選擇文件,選擇以前在ArcMap中保存的服務定義文件(.sd).而後點擊下一步。

      

      以後選擇發佈服務的名稱,和所在服務的目錄。

 

最後點擊下一步,發佈服務。在服務發佈以後登錄服務的rest頁面能夠查看服務的具體參數信息:

      接下來咱們就須要開始編碼來調用咱們這裏的GP服務實現繪製等值線的功能。到此咱們的繪製等值線的GP服務以及發佈完成,接下來就是編碼的過程。固然爲了確保您的GP服務可以正確運行,建議在編碼以前,經過ArcMap來驗證一下您的GP服務。驗證過程可參考以前的博文,鑑於篇幅在此再也不贅述。

3、  ArcGIS Runtime for Android 調用異步GP服務繪製等值線  

      本文開發環境:

  • ArcGIS Runtime for Android -10.2.2
  • Eclipse Java EE IDE for Web Developers - Version: Juno Service Release 2
  •  JDK-7
  •  Android 4.0.3及以上(ArcGIS Runtime for Android 10.2.2要求OPENGL 2.0環境,Android 4.0.3及以上版本的模擬器支持2.0的OPENGL)
  • ArcGIS Server 10.1

     調試過程在真機上實現

  3.1 ArcGIS Runtime for Android GP服務調用過程

     首先咱們須要瞭解GP服務的幾個問題:

    3.1.1.查看當前GP服務是異步仍是同步

    ArcGIS 的GP服務有異步和同步的兩種模式,默認狀況下(ArcGIS Server 10.1)使用的是異步模式。

    經過REST頁面的參數咱們也能夠知道GP服務時何種模式:

    

      或者

    

      Asynchronous表示的是異步模式,Submit Job也表示異步模式,他們是對應的。

  3.11.2 異步和同步的區別

      異步模式一般適用於模型較複雜,運行時間較長的GP服務,而同步適用於模型較簡單,運行時間較短的GP服務。

  •     對於同步的GP服務,須要等待服務執行完成,而後再去獲取結果
  •     對於異步的GP服務,無需客戶端等待,可是須要客戶端去查詢GP服務執行的狀態,若是執行完成,而後再去獲取結果,全部的過程須要開發人員本身編寫代碼,包括服務調用,狀態輪詢等。在ArcGIS Runtime for Android中並無提供相似與.net下的回調函數,以方便咱們獲取GP服務結果(若是您使用過C#+Silverlight/WPF/Win8/Windows Phone下的GP服務,咱們知道異步執行GP服務有個JobCompeleted事件,咱們能夠在該事件回調函數中寫獲取GP服務結果的代碼)。而ArcGIS Runtime for Android中並無這樣的事件供咱們使用。

3.2  ArcGIS Runtime 調用GP服務的詳細過程  

     ArcGIS Runtime for Android 中調用GP服務的核心類是:Geoprocessor.該類封裝了調用GP服務所需的方法。其中較爲重要的以下表所示:

                方法名稱        返回值 描述
  execute(List<GPParameter> parameters) GPResultResource 用於開始調用同步GP服務,GP服務執行完成以後,返回GP服務的結果
  submitJob(List<GPParameter> parameters) GPJobResource

用於開始調用異步GP服務,並返回本次GP服務調用的相關信息(如標示id,狀態等)。和同步不一樣的是每一次異步調用GP服務都會生成一個jobID來標示每一次GP調用的任務,經過這個jobId咱們能夠找到該次GP服務調用的狀態,結果。

checkJobStatus(String jobId) GPJobResource 檢查指定jobid對於GP服務的當前狀態,如服務是否提交,是否執行成功了,或者是否執行失敗了等。
getResultData(String jobId, String parameterName) GPParameter 根據指定的jobid,獲取指定的名稱的GP服務結果,注意全部的GP服務參數類型都繼承至GPParameter
getResultImage(String jobId, String parameterName) GPParameter 獲取GP服務的結果,並以圖片的方式返回(GPMapImageGPRasterDataLayer),主要用於結果地圖服務

 

 

 

 

 

 

 

 

 

 

Geoprocessor構造函數有兩個重載,都必須傳入GP服務的地址。

    下面咱們以上述繪製等值線的基礎爲例子,來具體說明如何讓調用GP服務。

    經過以前繪製等值線GP服務的REST頁面,咱們知道請求GP服務須要三個輸入參數和一個輸出參數(計算結果這裏即表示等值線),咱們先看一看輸入參數:

  • ForecastPoints: 預測點要素集,表示進行等值線繪製的點,且必須帶有concentration屬性,concentration屬性即爲點要素的屬性,表示改點表明的濃度值,類型是GPFeatureRecordSetLayer
  • Contour_interval :等值線間距,類型是:GPDouble
  • Smoothing_Tolerance :平滑容差,類型 GPLinearUnit 

     而在調用GP服務時,咱們須要將上述的參數添加到GPParameter類的集合中(List<GPParameter>),最後調用GP服務傳遞的是List< GPParameter>集合。

    下面咱們來構造上述GP服務參數,首先咱們新建一個類,取名:GPService,而後定義所所需的參數:

    private static final String FORECAST = "FORECAST";// 調試標示
    private Geoprocessor geoprocessor = null;// GP服務變量
    private GPFeatureRecordSetLayer forecastPointFeatures = null;// 預測點要素集
    private GPDouble contour_interval = null;// 等值線間距
    private GPLinearUnit smoothing_Tolerance = null;// 平滑容差
    private ArrayList<GPParameter> gpParameters = null;// GP服務參數集合
    public static GraphicsLayer contourLineGraphicsLayer;// 等值線圖層
    public GraphicsLayer gridPointGraphicsLayer;// 網格點圖層
    private static MapView mapView = null;// MapView控件
    private ArrayList<Graphic> forecastGraphicList = null;// 預測點集合
    double startx, starty;// 繪製網格的起始
    private Timer checkStatusTimer;// 時鐘,用於輪詢GP服務執行的狀態

並實例化:    

        //實例化參數
        geoprocessor = new Geoprocessor("http://192.168.1.181:6080/arcgis/rest/services/Interpolation/ContourServiceWithSmoothOption/GPServer/ContourToolWithSmoothOption");
        forecastPointFeatures = new GPFeatureRecordSetLayer("ForecastPoints");
        contour_interval = new GPDouble("Contour_interval");
        smoothing_Tolerance = new GPLinearUnit("Smoothing_Tolerance");
        gpParameters = new ArrayList<GPParameter>();
        gridPointGraphicsLayer = new GraphicsLayer(GraphicsLayer.RenderingMode.DYNAMIC);
        contourLineGraphicsLayer = new GraphicsLayer(GraphicsLayer.RenderingMode.DYNAMIC);
        forecastGraphicList = new ArrayList<Graphic>();
        startx = x;
        starty = y;
        
        //取得當前的MapView對象
        setMapView(map);
        //設置GP服務的默認參數
        contour_interval.setValue(3);//設置默認等值線間距是3
        smoothing_Tolerance.setDistance(30);//設置默認容差是30
        smoothing_Tolerance.setUnits("esriMeters");//設置容差單位爲米

說明:10.2的ArcGIS Runtime for Android 的API中對於GraphicsLayer有了很大的改進,在聲明GraPhicsLayer對象時能夠指定Gphics的渲染模式,當指定爲DYNAMIC時能夠極大優化Graphic的加載速度,從而提升用戶體驗。同時爲了簡化整個過程,這裏咱們用於繪製等值線的點,以及其對於的濃度值並非真實的數據,咱們將採用代碼來生成模擬的數據,具體過程是:用戶輸入一個點,以該點爲中心生成21x41個網格點。固然換成真實數據的過程同樣。下面是生成模擬數據的方法,這裏咱們使用了一個橢圓的函數來構造濃度值,所以咱們預期的等值線應該是一個一個的橢圓,此外還須要注意的是用於預測的點要素集必須包含concentration屬性,由於咱們這裏服務器端的GP服務是根據concentration屬性來繪製等值線的。要素的的屬性數據是以鍵值對的方式存放的。

    private void CreateGrid()
    {
        int drawOrder = 1;
        for (int i = -10; i <= 10; i++)
        {
            for (int j = -20; j <= 20; j++)
            {
                Map<String, Object> attributes = new HashMap<String, Object>();
                attributes.put("concentration", Math.pow(i, 2) / 10 + Math.pow(j, 2) / 20);
                attributes.put("xindex", i);
                attributes.put("yindex", j);
                drawOrder++;
                Graphic graphic = createGraphic(startx + i * 400, starty + j * 200, attributes, drawOrder);
                //網格點圖層
                gridPointGraphicsLayer.addGraphic(graphic);
                //預測點要素集
                forecastGraphicList.add(graphic);
            }
        }
    }

在構造完所需的參數以後,咱們添加集合輔助方法:

    //設置等值線間距參數
    public void setContourIntervalValue(double interval)
    {
        contour_interval.setValue(interval);
    }
    //設置平滑容差
    public void setSmoothToleranceValue(double tolerance, String units)
    {
        smoothing_Tolerance.setDistance(tolerance);
        smoothing_Tolerance.setUnits(units);
    }
                 //建立漸變的顏色
    public int[] createColorSet()
    {
        int[] colors = new int[6];
        for (int i = 0; i <= 5; i++)
        {
            colors[i] = Color.argb(254, i * 51, 255 - i * 51, 0);
        }
        return colors;
    }
    //構建用於分類渲染的樣式
    public ClassBreaksRenderer createClassBreaksRenderer(int[] colors, double maxValue, double minValue)
    {
        ClassBreaksRenderer contourBreaksRenderer = new ClassBreaksRenderer();
        double stepValue = (Math.ceil(maxValue) - Math.floor(minValue)) / colors.length;
        for (int i = 0; i < colors.length; i++)
        {
            ClassBreak classBreak = new ClassBreak();
            double max = (i + 1) * stepValue + Math.floor(minValue);
            double min = i * stepValue + Math.floor(minValue);
            classBreak.setClassMaxValue(max);
            classBreak.setClassMinValue(min);
            classBreak.setSymbol(new SimpleLineSymbol(colors[i], 3, com.esri.core.symbol.SimpleLineSymbol.STYLE.SOLID));
            contourBreaksRenderer.addClassBreak(classBreak);
        }
        return contourBreaksRenderer;
    }
    //夠着GraPhic對象,並輸入指定的屬性數據
    public Graphic createGraphic(double x, double y, Map<String, Object> attributes, int drawOrder)
    {

        Graphic graphic = new Graphic(new Point(x, y), new SimpleMarkerSymbol(Color.BLUE, 6, STYLE.CIRCLE), attributes, drawOrder);

        return graphic;
    }
     


注意:在ArcGIS Runtime for Android的API中,沒有單獨爲Graphic提供添加屬性(Attributes,若是您熟悉.net下的ArcGIS api,那麼您應該知道能夠經過Graphic的addAttributes方法來爲Graphic添加屬性),因爲沒有相似.net下的addAttributes方法,所以在須要給Graphic添加方法時只能經過兩種方式:

  • 在構造Graphic的時候就將咱們的屬性數據傳遞過去,好比本文使用的方法。
  • 經過將Graphic添加到GraPhicsLayer,而後調用GarphicsLayer的updateGraphic(int id, Map<String, Object> attributes)方法來更新Graphic的Attributes屬性。

定義好參數以及相關的輔助方法後,下面就來完成請求GP服務的代碼,定義一個StartGPService方法:

爲了使得請求GP服務時不影響前臺的UI線程,所以咱們從新new一個線程,由於若是直接在UI線程來添加用於預測的網格點(21x41)會有卡頓的現象。

 

public void StartGPService()
    {
        new Thread(new Runnable()
        {

            public void run()
            {
                // TODO Auto-generated method stub
                CreateGrid();
                // 輸入要素的要素類型,必須與GP服務所對應
                forecastPointFeatures.setGeometryType(Type.POINT);

                // 設置座標系爲102100座標系
                forecastPointFeatures.setSpatialReference(SpatialReference.create(SpatialReference.WKID_WGS84_WEB_MERCATOR_AUXILIARY_SPHERE));
                geoprocessor.setOutSR(forecastPointFeatures.getSpatialReference());
                geoprocessor.setProcessSR(forecastPointFeatures.getSpatialReference());
                // 將裁剪要素的座標系設置爲與預測點要素的座標系一致
                forecastPointFeatures.setGraphics(forecastGraphicList);

                for (Graphic testGraphic : forecastPointFeatures.getGraphics())
                {
                    Log.i(FORECAST,
                            "(" + testGraphic.getAttributeValue("xindex").toString() + "," + testGraphic.getAttributeValue("yindex").toString() + ")="
                                    + testGraphic.getAttributeValue("concentration").toString());
                }

                gpParameters.add(forecastPointFeatures);
                gpParameters.add(contour_interval);

                Log.i(FORECAST, "Submitting job thread is: " + Thread.currentThread().getName());

                getMapView().post(new Runnable()
                {
                    public void run()
                    {
                        // TODO Auto-generated method stub
                        getMapView().addLayer(gridPointGraphicsLayer);
                        Log.i(FORECAST, "ADD FORECAST POINT TO LAYER COMPLETED");
                    }
                });
                submitJobandPolling(geoprocessor, gpParameters);
            }
        }).start();

    }

 

這裏的submitJobandPolling方法以下,大體過程是:
1.提交當前的GP服務請求繪製等值線。

2.提交完成以後,取得當前的請求的JobId。

3.經過Timer,同時根據當前的JobId輪詢該GP服務的執行狀態

4.若是GP服務執行完成,則中止輪詢

5.若是GP服務執行成功,則獲取GP服務的結果:getResultData(jobId,"ContourLine"),獲得GPParameter

6.由於是等值線,因此結果是線要素,所以咱們將GPParameter轉爲GPFeatureRecordSetLayer。

7.讀取GPFeatureRecordSetLayer中的Graphic,即等值線

8.根據等值線的值(contour屬性)分類渲染等值線。

9.將等值線圖層添加到地圖中

代碼以下:

    void submitJobandPolling(final Geoprocessor gp, List<GPParameter> params)
    {
        try
        {
            GPJobResource gpjobResource = gp.submitJob(params);
            JobStatus jobstatus = gpjobResource.getJobStatus();
            final String jobid = gpjobResource.getJobID();
            Log.i(FORECAST, "jobid " + jobid);
            Log.i(FORECAST, "jobstatus " + jobstatus);
            if (jobstatus != JobStatus.SUCCEEDED)
            {
                Log.i(FORECAST, "Start Check GP Status...");
                checkStatusTimer = new Timer();
                checkStatusTimer.schedule(new TimerTask()
                {
                    @Override
                    public void run()
                    {
                        // TODO Auto-generated method stub
                        try
                        {
                            Log.i(FORECAST, "Checking Status is running...");

                            Log.i(FORECAST, "Polling thread is: " + Thread.currentThread().getName());

                            GPJobResource gpjobResource = gp.checkJobStatus(jobid);
                            JobStatus status = gpjobResource.getJobStatus();
                            Log.i(FORECAST, "jobstatus " + status);
                            boolean jobcomplete = false;

                            if (status == JobStatus.CANCELLED || status == JobStatus.DELETED || status == JobStatus.FAILED || status == JobStatus.SUCCEEDED || status == JobStatus.TIMED_OUT)
                            {
                                jobcomplete = true;
                            }
                            if (jobcomplete)
                            {
                                if (status == JobStatus.SUCCEEDED)
                                {
                                    Log.i(FORECAST, "START GETTING GP Service Result... ");

                                    GPParameter result = gp.getResultData(jobid, "ContourLine");
                                    Log.i(FORECAST, "GETTING GP Service Result COMPLETED");
                                    Log.i(FORECAST, "convert GP Service Result to GPFeatureRecordSetLayer");

                                    GPFeatureRecordSetLayer resultLayer = (GPFeatureRecordSetLayer) result;
                                    Log.i(FORECAST, "convert GP Service Result Type completed");

                                    Log.i(FORECAST, "Create Graphics from GP Service Result");
                                    double maxContour = 0;
                                    double minContour = 0;
                                    for (Graphic graphic : resultLayer.getGraphics())
                                    {
                                        if (Double.parseDouble(graphic.getAttributeValue("Contour").toString()) > maxContour)
                                        {
                                            maxContour = Double.parseDouble(graphic.getAttributeValue("Contour").toString());
                                        } else if (Double.parseDouble(graphic.getAttributeValue("Contour").toString()) < minContour)
                                        {
                                            minContour = Double.parseDouble(graphic.getAttributeValue("Contour").toString());
                                        }

                                        contourLineGraphicsLayer.addGraphic(graphic);
                                    }

                                    Log.i(FORECAST, "Create Render Colors");

                                    int[] colors = createColorSet();//
                                    for (int i = 0; i < colors.length; i++)
                                    {
                                        Log.i(FORECAST, "Color[" + i + "] = " + colors[i]);
                                    }
                                    Log.i(FORECAST, "MAXVALUE: " + maxContour + ";MINVALUE: " + minContour);
                                    ClassBreaksRenderer classBreaksRenderer = createClassBreaksRenderer(colors, maxContour, minContour);
                                    classBreaksRenderer.setField("Contour");
                                    classBreaksRenderer.setMinValue(0.0);

                                    contourLineGraphicsLayer.setRenderer(classBreaksRenderer);

                                    Log.i(FORECAST, "Create Graphics Completed");

                                    Log.i(FORECAST, "Add Graphics to MapLayer");

                                    getMapView().post(new Runnable()
                                    {
                                        public void run()
                                        {
                                            // TODO Auto-generated method stub
                                            getMapView().addLayer(contourLineGraphicsLayer);
                                            if (MainActivity.dialog.isShowing())
                                            {
                                                MainActivity.dialog.dismiss();
                                            }
                                            Log.i(FORECAST, "Add Graphics to map layer Completed");
                                        }
                                    });
                                } else
                                {
                                    Log.i(FORECAST, "GP failed");
                                }
                                checkStatusTimer.cancel();
                            }
                        } catch (Exception e)
                        {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                            if (MainActivity.dialog.isShowing())
                            {
                                MainActivity.dialog.dismiss();
                            }
                            checkStatusTimer.cancel();
                        }
                    }
                }, 1000, 2000);
            }
        } catch (Exception e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
            if (MainActivity.dialog.isShowing())
            {
                MainActivity.dialog.dismiss();
            }
        }
    }

到此關於GP服務的準備過程所有完成,下面咱們開始編寫調用的代碼,有了上面的工做,下面的就很容易了:
首先咱們看一下Android界面的佈局:

 

這裏加載本地數據爲預留功能。

而後咱們實例化一個GPService對象,傳入自動繪製預測點要素集所需的起點座標和MapView對象,而後設置等值線間距和平滑容差,最後調用GP服務便可。代碼以下:

    if (current_Point == null)
                {
                    Toast.makeText(MainActivity.this, "請先在地圖上添加計算計算原點", Toast.LENGTH_LONG).show();
                    return;
                }
                EditText intervalEditText=(EditText)MainActivity.this.findViewById(R.id.interval_value_EditText);
                EditText toleranceEditText=(EditText)MainActivity.this.findViewById(R.id.smooth_value_EditText);
                if(Double.parseDouble(intervalEditText.getText().toString())<=0){
                    Toast.makeText(MainActivity.this, "等值線間隔必須大於0", Toast.LENGTH_LONG).show();
                    return;
                }
                if(Double.parseDouble(toleranceEditText.getText().toString())<=0){
                    Toast.makeText(MainActivity.this, "平滑容差必須大於0,且注意單位是米", Toast.LENGTH_LONG).show();
                    return;
                }
                
                GPService gpservice = new GPService(current_Point.getX(), current_Point.getY(), mMapView);
                gpservice.setContourIntervalValue(Double.parseDouble(intervalEditText.getText().toString()));
                gpservice.setSmoothToleranceValue(Double.parseDouble(toleranceEditText.getText().toString()), "esriMeters");
                dialog= ProgressDialog.show(MainActivity.this, "繪製等值線...", "正在請求GIS服務....請稍後!");  
                gpservice.StartGPService();

最後等待咱們的等值線出來吧。

最後的效果圖:

 

 

 

總結:

關於GP服務,實際上不管Java平臺仍是C#平臺,不管Silverlight,Flex仍是JavaScript,不管Window Phone 仍是Android(IOS沒有了解過,不是很清楚,屌絲沒有蘋果機真啊....)他們調用GP服務的過程基本上都是同樣同樣的,注意是基本上。所以多少仍是有些差異,可是整體上來講都遵循這樣的過程:

1.聲明Geoprocessor變量,指定GP服務地址。

2.根據GP服務,聲明其所需的參數,並添加到GPParameter集合(其餘平臺名字也行稍有不同)

3.根據異步和同步,執行調用GP服務的方法

4.獲取GP服務的結果

瞭解了這個過程那麼您就知道GP服務該如何使用了。

 

一點題外話:

      再次寫博客,發現上一次仍是一年之前,不禁的感慨時間飛逝,這一年中,渾渾噩噩的感受就過去了,而後匆匆忙忙的找了份工做,而後立刻就要畢業了...留給本身的時間也已再也不太多,聽不少工做的朋友說工做了就身不禁己了,甚至連本身的時間也不是本身的啦,因此我想趁着本身尚未被剝削本身,乾點本身想幹的事情... 

     一年了,說長不長,說短不短,失去了不少,也收穫了不少,我想至少博客園收穫了100個粉絲,雖然很少,可是卻也是一筆不小的財富,或者這是筆者有生以來最大的粉絲羣了。所以我想既然寫了這個博客,那麼就得繼續努力,就得堅持。

     最後感謝您能讀完這篇博文,由於它確實長了點,可是仍是但願您能有所收穫,但願或多或少能幫助您解決遇到的問題,也但願您繼續關注個人博客,若是您以爲好就點個贊,有什麼建議也歡迎您留言一塊兒討論...

   

歡迎轉載,版權全部:博客園,Mr|Right

 本文地址:http://www.cnblogs.com/potential/p/3684076.html

相關文章
相關標籤/搜索