2016-04-18 22 views
0

我一直在嘗試一點點,現在只是讓我的應用程序再次啓動。我修改了我如何拉比特幣價格數據以允許用戶偏好。但是,因爲這樣做,我從我的TextView currentPriceDisplay元素方法中得到一個NullPointerException。 currentPriceDisplay.setText(getmBitcoinPrice());NullPointerException TextView.setText(CharSequence),不清楚它是如何仍然空

我修改了整個代碼中的值,以防止這個變量實際上爲空,我也檢查了我的nav_header_main.xml文件,看看我是否引用了正確的TextView。所以在這一點上,我非常難過,我不得不去日常工作。如果你可以看看我的代碼,看看你是否注意到任何好的東西。

MainActivity:

package com.instacoind.www.coind; 

import android.content.Context; 
import android.content.Intent; 
import android.content.SharedPreferences; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.preference.PreferenceManager; 
import android.support.annotation.Nullable; 
import android.support.design.widget.FloatingActionButton; 
import android.support.design.widget.Snackbar; 
import android.util.Log; 
import android.view.View; 
import android.support.design.widget.NavigationView; 
import android.support.v4.view.GravityCompat; 
import android.support.v4.widget.DrawerLayout; 
import android.support.v7.app.ActionBarDrawerToggle; 
import android.support.v7.app.AppCompatActivity; 
import android.support.v7.widget.Toolbar; 
import android.view.Menu; 
import android.view.MenuItem; 
import android.widget.TextView; 

import org.json.JSONException; 
import org.json.JSONObject; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.net.HttpURLConnection; 
import java.net.URL; 
import java.util.Map; 
import java.util.Set; 

public class MainActivity extends AppCompatActivity 
     implements NavigationView.OnNavigationItemSelectedListener { 

    private Double mBitcoinPrice = 0.0; 
    public Double getmBitcoinPrice(){ 
     return mBitcoinPrice; 
    } 
    public void setmBitcoinPrice(Double price){ 
     this.mBitcoinPrice = price; 
    } 
    private Double mBitcoinPriceOld = 0.0; 
    public Double getmBitcoinPriceOld(){ 
     return mBitcoinPriceOld; 
    } 
    public void setmBitcoinPriceOld(Double price){ 
     this.mBitcoinPriceOld = price; 
    } 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 
     setSupportActionBar(toolbar); 
     FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 
     fab.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View view) { 
       if(mBitcoinPrice != 0.0) { 
        Snackbar.make(view, "Last Change: " + priceChange(), Snackbar.LENGTH_LONG) 
          .setAction("Action", null).show(); 
       }else{ 
        Snackbar.make(view, "SYNC FAILED ERROR::01", Snackbar.LENGTH_LONG) 
          .setAction("Action", null).show(); 
       } 
      } 
     }); 

     DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 
     ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
       this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); 
     drawer.setDrawerListener(toggle); 
     toggle.syncState(); 

     NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); 
     navigationView.setNavigationItemSelectedListener(this); 
    } 

    @Override 
    public void onBackPressed() { 
     DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 
     if (drawer.isDrawerOpen(GravityCompat.START)) { 
      drawer.closeDrawer(GravityCompat.START); 
     } else { 
      super.onBackPressed(); 
     } 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.main, menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     // Handle action bar item clicks here. The action bar will 
     // automatically handle clicks on the Home/Up button, so long 
     // as you specify a parent activity in AndroidManifest.xml. 
     int id = item.getItemId(); 

     //noinspection SimplifiableIfStatement 
     if (id == R.id.action_settings) { 
      Intent start_settings = new Intent(this, SettingsActivity.class); 
      startActivity(start_settings); 
      return true; 
     } 

     return super.onOptionsItemSelected(item); 
    } 

    @Override 
    protected void onStart(){ 
     super.onStart(); 
     updatePrice(); 
    } 

    @SuppressWarnings("StatementWithEmptyBody") 
    @Override 
    public boolean onNavigationItemSelected(MenuItem item) { 
     // Handle navigation view item clicks here. 
     int id = item.getItemId(); 

     if (id == R.id.nav_camera) { 
      // Handle the camera action 
     } else if (id == R.id.nav_gallery) { 

     } 

     DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 
     drawer.closeDrawer(GravityCompat.START); 
     return true; 
    } 

    public void updatePrice(){ 
     GetBitcoinPrice worker = new GetBitcoinPrice(); 
     worker.execute(getPrefFiat(this), getPrefPriceIndex(this)); 
     refreshPriceDisplays(); 
    } 
    public static String getPrefFiat(Context context){ 
     SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 
     return prefs.getString(context.getString(R.string.pref_currency_key), 
       context.getString(R.string.pref_currency_def)); 
    } 
    public static String getPrefPriceIndex(Context context){ 
     SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 
     return prefs.getString(context.getString(R.string.pref_source_key), 
       context.getString(R.string.pref_source_default)); 
    } 
    public String priceChange(){ 
     Double past = getmBitcoinPriceOld(); 
     Double pres = getmBitcoinPrice(); 
     Double change = 0.0; 
     String fin = "price_change"; 
     if(past != null){ 
      if(pres >= past){ 
       change = pres - past; 
       fin = "+ " + Double.toString(change); 
      }else if(pres <= past){ 
       change = past - pres; 
       fin = "- " + Double.toString(change); 
      } 
     }else{ 
      setmBitcoinPriceOld(getmBitcoinPrice()); 
     } 
     return fin; 
    } 
    public void refreshPriceDisplays(){ 
     TextView PriceDisplay = (TextView) findViewById(R.id.current_price_display); 
     String error = "No Bitcoin Price"; 
     try { 
      Log.v("RefreshPriceDisplays", "mBitcoinPrice: " + Double.toString(getmBitcoinPrice())); 
      PriceDisplay.setText(Double.toString(getmBitcoinPrice())); 
     }catch(NullPointerException e) { 
      Log.v("RefreshPriceDisplays", "mBitcoinPrice NULL"); 
      PriceDisplay.setText("ERR"); 
     } 
    } 


    private class GetBitcoinPrice extends AsyncTask<String, Void, Double> { 

     public String mPrefFiat; 
     public String mPrefIndex; 

     protected Double doInBackground(String... params) { 

      // These two need to be declared outside the try/catch 
      // so that they can be closed in the finally block. 
      HttpURLConnection urlConnection = null; 
      BufferedReader reader = null; 

      // Will contain the raw JSON response as a string. 
      String bitcoinJsonStr = null; 
      this.mPrefFiat = params[0]; 
      this.mPrefIndex = params[1]; 



      try { 
       // Construct the URL for the OpenWeatherMap query 
       // Possible parameters are avaiable at OWM's forecast API page, at 
       // http://openweathermap.org/API#forecast 
       URL url = new URL(buildUrl(this.mPrefFiat,this.mPrefIndex)); 

       // Create the request to Index Source, and open the connection 
       urlConnection = (HttpURLConnection) url.openConnection(); 
       urlConnection.setRequestMethod("GET"); 
       urlConnection.connect(); 

       // Read the input stream into a String 
       InputStream inputStream = urlConnection.getInputStream(); 
       StringBuffer buffer = new StringBuffer(); 
       if (inputStream == null) { 
        // Nothing to do. 
        bitcoinJsonStr = null; 
       } 
       reader = new BufferedReader(new InputStreamReader(inputStream)); 

       String line; 
       while ((line = reader.readLine()) != null) { 
        // Since it's JSON, adding a newline isn't necessary (it won't affect parsing) 
        // But it does make debugging a *lot* easier if you print out the completed 
        // buffer for debugging. 
        buffer.append(line + "\n"); 
       } 

       if (buffer.length() == 0) { 
        // Stream was empty. No point in parsing. 
        bitcoinJsonStr = null; 
       } 
       bitcoinJsonStr = buffer.toString(); 
      } catch (IOException e) { 
       Log.e("GetBitcoinPrice", "Error ", e); 
       // If the code didn't successfully get the price index data, there's no point in attemping 
       // to parse it. 
       bitcoinJsonStr = null; 
      } finally { 
       if (urlConnection != null) { 
        urlConnection.disconnect(); 
       } 
       if (reader != null) { 
        try { 
         reader.close(); 
        } catch (final IOException e) { 
         Log.e("GetBitcoinPrice", "Error closing stream", e); 
        } 
       } 
      } 
      if(this.mPrefIndex == "https://api.coindesk.com/v1/bpi/currentprice.json") 
       return parseCoindesk(bitcoinJsonStr); 
      else if (this.mPrefIndex == "https://api.coinbase.com/v2/prices/spot?currency=") 
       return parseCoinbase(bitcoinJsonStr); 
      else if (this.mPrefIndex == "https://www.okcoin.com/api/v1/ticker.do?symbol=") 
       return parseOkcoin(bitcoinJsonStr); 
      else if (this.mPrefIndex == "https://cex.io/api/ticker/BTC/") 
       return parseCex(bitcoinJsonStr); 
      else 
       return 0.0; 
     } 
     private Double parseCex(String bitcoinJsonStr){ 
      Double price = 0.0; 

      try { 
       JSONObject obj = new JSONObject(bitcoinJsonStr); 
       price = obj.getDouble("bid"); 
       Log.v("ConvertPriceStr", "Current Price is " + Double.toString(price)); 
       if (price == null){ 
        Log.e("CEXParsing", "Parsed to Null"); 
       } 

      }catch (JSONException x){ 
       Log.e("ConvertPriceStr", "Error Parsing bitcoinJsonStr"); 
      } 
      return price; 
     } 
     private Double parseCoindesk(String bitcoinJsonStr){ 
      Double price = 0.0; 

      try { 
       JSONObject obj = new JSONObject(bitcoinJsonStr); 
       JSONObject bpi = obj.getJSONObject("bpi"); 
       JSONObject usd = bpi.getJSONObject("USD"); 
       price = usd.getDouble("rate_float"); 
       Log.v("ConvertPriceStr", "Current Price is " + Double.toString(price)); 

      }catch (JSONException x){ 
       Log.e("ConvertPriceStr", "Error Parsing bitcoinJsonStr"); 
      } 
      return price; 
     } 
     private Double parseCoinbase(String bitcoinJsonStr){ 
      Double price = 0.0; 
      try{ 
       JSONObject obj = new JSONObject(bitcoinJsonStr); 
       JSONObject bpi = obj.getJSONObject("data"); 
       price = bpi.getDouble("amount"); 
       Log.v("ParseCoinbase", "Current Price is " + Double.toString(price)); 
      }catch(JSONException e){ 
       Log.e("ParseCoinbase", "Error Parsing bitcoinJsonStr"); 
      } 
      return price; 
     } 
     private Double parseOkcoin(String bitcoinJsonStr){ 
      Double price = 0.0; 
      try{ 
       JSONObject obj = new JSONObject(bitcoinJsonStr); 
       JSONObject bpi = obj.getJSONObject("ticker"); 
       price = bpi.getDouble("buy"); 
       Log.v("ParseOkCoin", "Current Price is " + Double.toString(price)); 
      }catch(JSONException e){ 
       Log.e("ParseOkCoin", "Error Parsing bitcoinJsonStr"); 
      } 
      return price; 
     } 
     private String buildUrl(String prefFiat, String prefIndex){ 
      String url = null; 
      try { 
       if (prefIndex == "https://api.coinbase.com/v2/prices/spot?currency=") { 
        url = prefIndex + prefFiat; 
       } else if (prefIndex == "https://api.coindesk.com/v1/bpi/currentprice.json") { 
        url = prefIndex + prefFiat; 
       } else if (prefIndex == "https://www.okcoin.com/api/v1/ticker.do?symbol=") { 
        String modFiat; 
        modFiat = "btc_" + prefFiat; 
        url = prefIndex + modFiat; 
       } else if (prefIndex == "https://cex.io/api/ticker/BTC/") { 
        String modFiat; 
        modFiat = prefIndex + prefFiat; 
        url = modFiat; 
       } else { 
        url = "https://api.coindesk.com/v1/bpi/currentprice.json"; 
       } 
      }catch(NullPointerException e){ 
       Log.e("URL Builder", "Error Constructing Proper URL", e); 
      } 
      return url; 
     } 

     protected void onPostExecute(Double result){ 
      setmBitcoinPriceOld(getmBitcoinPrice()); 
      setmBitcoinPrice(result); 
     } 
    } 
} 

XML文件:

activity_main.xml中:

<include 
     layout="@layout/app_bar_main" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" /> 

    <android.support.design.widget.NavigationView 
     android:id="@+id/nav_view" 
     android:layout_width="wrap_content" 
     android:layout_height="match_parent" 
     android:layout_gravity="start" 
     android:fitsSystemWindows="true" 
     app:headerLayout="@layout/nav_header_main" 
     app:menu="@menu/activity_main_drawer" /> 

</android.support.v4.widget.DrawerLayout> 

app_bar_main.xml:

<?xml version="1.0" encoding="utf-8"?> 
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:fitsSystemWindows="true" 
    tools:context="com.instacoind.www.coind.MainActivity"> 

    <android.support.design.widget.AppBarLayout 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:theme="@style/AppTheme.AppBarOverlay"> 

     <android.support.v7.widget.Toolbar 
      android:id="@+id/toolbar" 
      android:layout_width="match_parent" 
      android:layout_height="?attr/actionBarSize" 
      android:background="?attr/colorPrimary" 
      app:popupTheme="@style/AppTheme.PopupOverlay" /> 

    </android.support.design.widget.AppBarLayout> 

    <include layout="@layout/content_main" /> 

    <android.support.design.widget.FloatingActionButton 
     android:id="@+id/fab" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="bottom|end" 
     android:layout_margin="@dimen/fab_margin" 
     android:src="@drawable/refresh_60_60" /> 

</android.support.design.widget.CoordinatorLayout> 

content_main.xml:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:paddingBottom="@dimen/activity_vertical_margin" 
    android:paddingLeft="@dimen/activity_horizontal_margin" 
    android:paddingRight="@dimen/activity_horizontal_margin" 
    android:paddingTop="@dimen/activity_vertical_margin" 
    app:layout_behavior="@string/appbar_scrolling_view_behavior" 
    tools:context="com.instacoind.www.coind.MainActivity" 
    tools:showIn="@layout/app_bar_main"> 

</RelativeLayout> 

nav_header_main.xml:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="@dimen/nav_header_height" 
    android:background="@drawable/side_nav_bar" 
    android:gravity="bottom" 
    android:orientation="vertical" 
    android:paddingBottom="@dimen/activity_vertical_margin" 
    android:paddingLeft="@dimen/activity_horizontal_margin" 
    android:paddingRight="@dimen/activity_horizontal_margin" 
    android:paddingTop="@dimen/activity_vertical_margin" 
    android:theme="@style/ThemeOverlay.AppCompat.Dark"> 

    <ImageView 
     android:id="@+id/coin_display" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentTop="true" 
     android:layout_alignParentStart="true" 
     android:layout_alignParentLeft="true" 
     android:paddingTop="@dimen/nav_header_vertical_spacing" 
     android:src="@drawable/bitcoin_80_80" 
     android:contentDescription="@string/coin_content_description"/> 

    <TextView 
     android:id="@+id/bpi_source_display" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:paddingTop="@dimen/nav_header_vertical_spacing" 
     android:text="BPI_Source" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentStart="true" 
     android:layout_alignParentBottom="true" 
     android:textAppearance="@style/TextAppearance.AppCompat.Body1" /> 

    <TextView 
     android:id="@+id/def_currency_display" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:paddingLeft="5dp" 
     android:layout_toRightOf="@+id/bpi_source_display" 
     android:layout_toEndOf="@+id/bpi_source_display" 
     android:layout_alignParentBottom="true" 
     android:text="DEF_Currency" /> 
    <TextView 
     android:id="@+id/current_price_display" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:paddingTop="40dp" 
     android:paddingStart="80dp" 
     android:paddingLeft="80dp" 
     android:layout_alignParentEnd="true" 
     android:layout_alignParentRight="true" 
     android:layout_toRightOf="@+id/coin_display" 
     android:textAppearance="@style/TextAppearance.AppCompat.Headline"/> 

</RelativeLayout> 
+0

'currentPriceDisplay.setText(getmBitcoinPrice());' - 此行在發佈的代碼中無處。 –

+0

從你的'AsyncTask'' onPostExecute'方法調用'refreshPriceDisplays()'方法 – Rustam

+0

@MikeM。它在'refreshPriceDisplays()'方法內部,在正確的語法中使用不同語法的道歉是'PriceDisplay.setText(getmBitcoinPrice());'。 – dbrad

回答

0

好吧,比我想象的要長的時間,直到我真的可以坐下來再次工作。爲了拖延我的腳後跟抱歉,我已經解決了墜機問題。

這是因爲我在onCreate/AsyncTask完成之前調用了我的refreshPriceDisplays()方法。一旦我將refreshPriceDisplays()轉移到我的onPostExecute中,一切都變得很好。

至於這個問題的第一個答案,你提出了一些關於我的邏輯好點,他們已經解決了,非常感謝你的投入!

1

我認爲這個問題是來自這四個方法: parseCoindesk,parseCoinbase,parseCex,parseOkcoin

在每個這些(例如parseCex):

  if (price == null){ 
       Log.e("CEXParsing", "Parsed to Null");// You just print a Log! 
      } 

     }catch (JSONException x){ 
      Log.e("ConvertPriceStr", "Error Parsing bitcoinJsonStr"); 
     } 
     return price;//when price is null it can still return! 
    } 

所以,你應該嘗試像這樣回覆:

return price == null ? 0.0 : price; 
+0

你可能是對的,多麼優雅的回報聲明。如果價格== null,我應該添加歷史價格數據來使用? historicalPrice'。不幸的是,直到1130年左右,我才能證明這個理論。 – dbrad

相關問題